<template>
	<view>
		<view class="container" v-if="!isWifiSetting && !isApiSetting">
		  <view v-if="loading" class="loading-container">
		    <view class="scanning-animation">
		      <view class="scan-circle"></view>
		      <image class="scan-icon" src="/static/images/device-type-icons.svg#thermostat" mode="aspectFit"></image>
		    </view>
		    <text class="scanning-text">{{ loadingText.contentrefresh }}</text>
		  </view>
		  
		  <scroll-view v-else class="device-list" scroll-y>
		    <view class="device-item" v-for="(device, index) in devices" :key="index" @click="selectDevice(device)">
		      <view class="device-icon-wrapper">
		        <image class="device-icon" src="/static/images/robot.svg" mode="aspectFit"></image>
		      </view>
		      <view class="device-info">
		        <text class="device-name">{{ device.name }}</text>
		      </view>
		    </view>
		  </scroll-view>
		</view>
		
		<view class="container-wifi" v-if="isWifiSetting">
			<uni-forms ref="form" :model="formData">
				<uni-forms-item label="WiFi名称" name="ssid" required>
					<uni-easyinput v-model="formData.ssid" placeholder="请输入WiFi名称" />
				</uni-forms-item>
				
				<uni-forms-item label="密码" name="password" required>
					<uni-easyinput type="password" v-model="formData.password" placeholder="请输入WiFi密码" />
				</uni-forms-item>
				
				<button class="submit-btn" @click="submitWifiForm">开始配网</button>
			</uni-forms>
		</view>
	</view>
</template>

<script>
export default {
  data() {
    return {
      loading: true,
      loadingText: { contentdown: '正在搜索设备', contentrefresh: '正在搜索', contentnomore: '搜索完成' },
      devices: [],

      connectId: "",
      SERVICE_UUID: "",
      CHARACTERISTIC_UUID: "",

      // 是否已连接
      connected: false,
      inited: false,
      devices: [],
      // 当前连接的设备id
      // 接收到的数据
      received: "",
	  
	  // 是否是WIFI配置
	  isWifiSetting: false,
	  // 是否是API配置
	  isApiSetting: false,
	  
	  formData: {
		  // WIFI账号
		  ssid: '',
		  // WIFI密码
		  password: ''
	  }
    }
  },
  
  onReady() {
  	//this.$refs.form.setRules(this.rules)
  },
  
  onLoad() {
    this.main();
  },
	
  onUnload() {
    this.disConnect();
  },
  
  methods: {
    async selectDevice(device) {
		console.log('即将连接蓝牙：', device);
		// 如果当前有连接的设备，需要先断开
		if (this.connected) {
		  await this.disConnect();
		}
		if (!this.inited) {
		  await this.initBlue();
		  // 扫描蓝牙设备
		  // this.scan();
		}
		this.connectId = device.deviceId;
		await this.connect();
		this.isApiSetting = false;
		this.isWifiSetting = true;
    },

    async main() {
      // 初始化蓝牙
      await this.initBlue();
    },

    // 开启蓝牙
    initBlue() {
      console.log('初始化蓝牙开始...')
      const _this = this;
      return new Promise((resolve) => {
        uni.openBluetoothAdapter({
          success(res) {
            console.log('初始化蓝牙成功')
            _this.inited = true;
            // 扫描蓝牙设备
            _this.scan();
            resolve();
          },
          fail(err) {
            console.log('初始化蓝牙失败', err)
            uni.showModal({
              title: '失败提示',
              content: "初始化蓝牙失败",
              showCancel: false
            });
          }
        })
      })
    },

    // 扫描设备
    async scan() {
      const _this = this;
      if (!_this.inited) {
        await _this.initBlue();
      }

      uni.startBluetoothDevicesDiscovery({
        success(res) {
          console.log('启动搜索')
        },
        fail(err) {
          console.log('启动搜索失败', err)
          uni.showModal({
            title: '失败提示',
            content: "启动搜索失败",
            showCancel: false
          });
        }
      })
      
      // 收到到蓝牙设备后的回调
      uni.onBluetoothDeviceFound(({devices}) => {
        _this.devices.push(...devices);
        // 去重
        _this.devices = [..._this.devices].reduce((pre, cur) => {
          console.log(cur.name)
		  if ((pre.find(item => item.deviceId == cur.deviceId)) == null && (cur.name == "Arduino" || cur.name.startsWith("LMB-Robot"))) {
            pre.push(cur)
          }
          return pre;
        }, [])
        _this.loading = false;
      })
    },
	
	// 连接蓝牙
	connect() {
	  const _this = this;
	  console.log('设备id', _this.connectId);
	  return new Promise((resolve) => {
	    uni.showLoading({
	      title: '连接中...'
	    });
	    uni.createBLEConnection({
	      timeout: 5000,
	      // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
	      deviceId: _this.connectId,
	      success(res) {
	        console.log("连接成功:", res);
	
	        // 必须延时 1000，不然拿不到服务信息
	        setTimeout(() => {
	          _this.connected = true;
	
	          // 获取服务的 ID, 会有多个 ID, 使用在硬件中定义的那个
	          // 这里有个问题问题，getBLEDeviceServices和getBLEDeviceCharacteristics如果拆出去后无法正常运行，所以只能写到 success 里面
	          uni.getBLEDeviceServices({
	            deviceId: _this.connectId,
	            success(res) {
	              // console.log('所有服务:', res)
	              if (!res.services.length) {
	                uni.showModal({
	                  title: '失败提示',
	                  content: "获取的服务长度为 0 ",
	                  showCancel: false
	                });
	                return;
	              }
	              // 这里一般是获取最后一个，板子里把自定义的放到了最后
	              // 但不是所有情况都这样，具体需要看板子代码里面的定义
	              _this.SERVICE_UUID = res.services[res.services.length - 1].uuid;
	
	              // 必须延时 100，不然拿不到特征信息
	              setTimeout(() => {
	                // 获取服务下的特征的 ID, 会有多个 ID, 使用在硬件中定义的那个
	                uni.getBLEDeviceCharacteristics({
	                  deviceId: _this.connectId,
	                  serviceId: _this.SERVICE_UUID,
	                  success(res) {
	                    // console.log('所有特征:', res);
	
	                    // 停止扫描设备, 否则会浪费性能
	                    uni.stopBluetoothDevicesDiscovery({})
	
	                    // 一般直接获取第一个就行
	                    _this.CHARACTERISTIC_UUID = res.characteristics[0].uuid;
	
	
	                    // 读取设备的特征值
	                    uni.readBLECharacteristicValue({
	                      // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
	                      deviceId: _this.connectId,
	                      // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
	                      serviceId: _this.SERVICE_UUID,
	                      // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
	                      characteristicId: _this.CHARACTERISTIC_UUID,
	                      success(res) {
	                        console.log('读取特征值成功:', res)
	                      },
	                      fail(err) {
	                        console.log('读取特征值失败：', err)
	                      }
	                    })
	
	                    // 监听特征值的变化
	                    uni.notifyBLECharacteristicValueChange({
	                      state: true, // 启用 notify 功能
	                      // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
	                      deviceId: _this.connectId,
	                      // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
	                      serviceId: _this.SERVICE_UUID,
	                      // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
	                      characteristicId: _this.CHARACTERISTIC_UUID,
	                      success(res) {
	                        console.log('监听特征值成功:', res)
	
	                        // 持续监听特征值变化 必须写到这个回调中，不然一些便宜的板子在第二次更改特征后，uniapp 中接收不到。
	                        uni.onBLECharacteristicValueChange(function (characteristic) {
	                          const str_data = String.fromCharCode.apply(null, new Uint8Array(characteristic.value));
	                          console.log("特征值：", str_data);
	                          _this.received = str_data;
	                        })
	                      },
	                      fail(err) {
	                        console.log('监听特征值失败：', err)
	                      }
	                    })
	
	                    // 监听蓝牙连接状态
	                    uni.onBLEConnectionStateChange(function (res) {
	                      // 该方法回调中可以用于处理连接意外断开等异常情况
	                      console.log(`设备连接状态改变 ${res.deviceId}, connected: ${res.connected}`)
	                    })
	                  },
	                  fail(err) {
	                    console.log('获取特征值失败', err)
	                    uni.showModal({
	                      title: '失败提示',
	                      content: "获取特征值失败 " + err.errMsg,
	                      showCancel: false
	                    });
	                  }
	                })
	              }, 100)
	            },
	            fail(err) {
	              console.log('获取蓝牙服务失败', err)
	              uni.showModal({
	                title: '失败提示',
	                content: "获取蓝牙服务失败 " + err.errMsg,
	                showCancel: false
	              });
	            }
	          })
	
	          resolve();
	        }, 1000);
	      },
	      fail(err) {
	        _this.connected = true;
	        _this.connectId = null
	        _this.SERVICE_UUID = null
	        _this.CHARACTERISTIC_UUID = null
	        console.log('连接服务失败：', err)
	        uni.showModal({
	          title: '失败提示',
	          content: "连接服务失败 " + err.errMsg,
	          showCancel: false
	        });
	      },
	      complete() {
	        uni.hideLoading();
	      }
	    })
	  })
	},
	
    // 断开连接
    disConnect() {
      const _this = this;
      if (!_this.connectId) return;
      uni.showLoading({
        title: 'loading...'
      });
      return new Promise((resolve) => {
        uni.closeBLEConnection({
          deviceId: _this.connectId,
          success(res) {
            console.log("断开连接成功：", res)

            // 断开后必须释放蓝牙资源，不然再点击连接就连不上了
            // https://uniapp.dcloud.net.cn/api/system/bluetooth.html
            uni.closeBluetoothAdapter({
              success() {
                console.log('释放蓝牙资源成功')
                _this.connected = false;
                _this.connectId = null
                _this.SERVICE_UUID = null
                _this.CHARACTERISTIC_UUID = null;
                _this.inited = false;
                _this.received = false;


                // 延时下保险点
                setTimeout(() => {
                  uni.hideLoading();
                  resolve();
                }, 600)
              },
              fail() {
                uni.hideLoading();
              }
            })

          },
          fail(err) {
            uni.hideLoading();
            console.log('断开连接失败：', err)
            uni.showModal({
              title: '失败提示',
              content: "断开连接失败 " + err.errMsg,
              showCancel: false
            });
          }
        })
      })
    },
	
	submitWifiForm() {
		if(!this.formData.ssid){
			uni.showToast({
				title: '请填写WIFI名称',
				icon: 'error'
			})
			return;
		}
		if(!this.formData.password){
			uni.showToast({
				title: '请填写WIFI密码',
				icon: 'error'
			})
			return;
		}
		uni.showLoading({
			title: '正在配网...'
		})
		this.sendWifi(this.formData.ssid + ":" + this.formData.password);
	},
	
	sendWifi(ssidAndPwd) {
		const _this = this;
		console.log("设备id:", this.connectId)
		console.log("服务id:", this.SERVICE_UUID)
		console.log("特征id:", this.CHARACTERISTIC_UUID)
	
		// 发送数据
		const reqData = _this.str2ab(ssidAndPwd);
		uni.writeBLECharacteristicValue({
			// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
			deviceId: this.connectId,
			// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
			serviceId: this.SERVICE_UUID,
			// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
			characteristicId: this.CHARACTERISTIC_UUID,
			// 这里的value是ArrayBuffer类型
			value: reqData,
			success(res) {
				console.log('特征值写入成功：', res.errMsg);
				uni.hideLoading()
				uni.showToast({
					title: '配网成功',
					icon: 'success'
				})
				uni.navigateBack();
			}
		})
	},
	
	// 字符串转为ArrayBuffer对象，参数为字符串
	str2ab(str) {
		var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
		var bufView = new Uint16Array(buf);
		for (var i = 0, strLen = str.length; i < strLen; i++) {
			bufView[i] = str.charCodeAt(i);
		}
		return buf;
	}
  }
}
</script>

<style>
.container {
  padding: 30rpx;
  background: linear-gradient(135deg, #f8f8f8 0%, #ffffff 100%);
  min-height: 100vh;
}

.loading-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 160rpx;
}

.scanning-animation {
  position: relative;
  width: 240rpx;
  height: 240rpx;
  margin-bottom: 40rpx;
}

.scan-circle {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 6rpx solid #007aff;
  border-radius: 50%;
  animation: scan 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
  box-shadow: 0 0 20rpx rgba(0,122,255,0.2);
}

.scan-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100rpx;
  height: 100rpx;
  transform: translate(-50%, -50%);
  opacity: 0.9;
}

.scanning-text {
  font-size: 32rpx;
  color: #333;
  margin-top: 60rpx;
  font-weight: 500;
  letter-spacing: 2rpx;
}

.device-list {
  height: calc(100vh - 60rpx);
  padding: 20rpx 0;
}

.device-item {
  display: flex;
  align-items: center;
  padding: 36rpx;
  margin-bottom: 24rpx;
  background-color: #fff;
  border-radius: 20rpx;
  box-shadow: 0 6rpx 16rpx rgba(0,0,0,0.06);
  transition: all 0.3s ease;
}

.device-item:active {
  transform: scale(0.98);
  box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04);
}

.device-icon-wrapper {
  width: 96rpx;
  height: 96rpx;
  background: linear-gradient(135deg, rgba(0,122,255,0.1) 0%, rgba(0,122,255,0.05) 100%);
  border-radius: 24rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.device-icon {
  width: 56rpx;
  height: 56rpx;
}

.device-info {
  flex: 1;
  margin-left: 28rpx;
}

.device-name {
  font-size: 34rpx;
  font-weight: 600;
  color: #333;
  margin-bottom: 10rpx;
}

.device-desc {
  font-size: 26rpx;
  color: #666;
}

.device-status {
  padding: 10rpx 28rpx;
  background: linear-gradient(135deg, rgba(0,122,255,0.1) 0%, rgba(0,122,255,0.05) 100%);
  color: #007aff;
  font-size: 26rpx;
  border-radius: 28rpx;
  font-weight: 500;
}

.status-connected {
  background: linear-gradient(135deg, rgba(76,217,100,0.1) 0%, rgba(76,217,100,0.05) 100%);
  color: #4cd964;
}

@keyframes scan {
  0% {
    transform: scale(0.6);
    opacity: 0.9;
  }
  50% {
    transform: scale(1.4);
    opacity: 0.3;
  }
  100% {
    transform: scale(0.6);
    opacity: 0.9;
  }
}


.container-wifi {
	padding: 40rpx;
	background-color: #f8f8f8;
	min-height: 100vh;
}
	
:deep(.uni-forms-item) {
	margin-bottom: 30rpx;
	padding: 30rpx;
	background-color: #fff;
	border-radius: 16rpx;
	box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
	display: flex;
	align-items: center;
}


:deep(.uni-forms-item__label) {
	font-size: 28rpx;
	color: #333;
	font-weight: 500;
	width: 160rpx !important;
	padding-right: 20rpx;
	line-height: 88rpx;
	text-align: right;
}

:deep(.uni-forms-item__content) {
	flex: 1;
}

:deep(.uni-easyinput__content) {
	background-color: #f5f5f5 !important;
	border-radius: 12rpx !important;
	height: 88rpx !important;
}

:deep(.uni-easyinput__placeholder-class) {
	font-size: 28rpx;
}

.submit-btn {
	margin-top: 60rpx;
	background-color: #007aff;
	color: white;
	padding: 32rpx 0;
	border-radius: 50rpx;
	font-size: 32rpx;
	text-align: center;
	box-shadow: 0 8rpx 16rpx rgba(0, 122, 255, 0.2);
	transition: all 0.3s ease;
}

.submit-btn:active {
	transform: translateY(2rpx);
	box-shadow: 0 4rpx 8rpx rgba(0, 122, 255, 0.2);
}
</style>